package com.jrx.anytxn.investor.handler.impl;

import com.jrx.anytxn.common.constant.CommonContants;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.uitl.*;
import com.jrx.anytxn.customer.dto.customer.CustomerFirstLevelRes;
import com.jrx.anytxn.customer.dto.customer.CustomerRes;
import com.jrx.anytxn.customer.dto.customer.CustomerSecondLevelRes;
import com.jrx.anytxn.customer.service.ICustomerService;
import com.jrx.anytxn.feign.api.request.FunResultCallBackRequest;
import com.jrx.anytxn.feign.api.service.IUserApiService;
import com.jrx.anytxn.feign.gateway.bean.ApiResponse;
import com.jrx.anytxn.feign.gateway.bean.BaseApiResponse;
import com.jrx.anytxn.feign.gateway.bean.FreezeInfo;
import com.jrx.anytxn.feign.gateway.request.CoreRequest10;
import com.jrx.anytxn.feign.gateway.request.PartnerRequest01;
import com.jrx.anytxn.feign.gateway.response.CoreResponse10;
import com.jrx.anytxn.feign.gateway.service.IInnerGatewayService;
import com.jrx.anytxn.feign.param.request.HandleInvestorLimitReq;
import com.jrx.anytxn.feign.param.response.HandleInvestorLimitRes;
import com.jrx.anytxn.feign.param.service.IAnyTxnParamService;
import com.jrx.anytxn.i18n.response.TxnRespResult;
import com.jrx.anytxn.investor.bean.InvestorFundRouteBean;
import com.jrx.anytxn.investor.bean.InvestorRecoverBean;
import com.jrx.anytxn.investor.constant.TransBizConstant;
import com.jrx.anytxn.investor.dto.loan.SaveFundRouteReq;
import com.jrx.anytxn.investor.dto.loan.SaveFundRouteRes;
import com.jrx.anytxn.investor.entity.TlCustomerInvestorLimit;
import com.jrx.anytxn.investor.entity.TlFundRestraintLog;
import com.jrx.anytxn.investor.entity.TlFundRouteLog;
import com.jrx.anytxn.investor.entity.TlInvestorLoanApproveLog;
import com.jrx.anytxn.investor.handler.IInvestorLoanRouteHandler;
import com.jrx.anytxn.investor.mapper.ext.ExtTlFundRouteLogMapper;
import com.jrx.anytxn.investor.service.IInvestorCustomerLimitService;
import com.jrx.anytxn.investor.service.IInvestorLoanService;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.dto.investor.FundTableRes;
import com.jrx.anytxn.param.entity.PrFundFactor;
import com.jrx.anytxn.param.entity.PrInvestorTable;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrProductFund;
import com.jrx.anytxn.param.service.investor.IFundTableService;
import com.jrx.anytxn.param.service.investor.IPrInvestorTableService;
import com.jrx.anytxn.param.service.product.IProductTableService;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.ribbon.config.GrayVersionConfig;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 联合贷放款路由处理接口
 *
 * @author liuyang
 * @date 2020-06-02
 */
@Service
public class InvestorLoanRouteHandlerImpl implements IInvestorLoanRouteHandler {

    private static final Logger logger = LoggerFactory.getLogger(InvestorLoanRouteHandlerImpl.class);

    @Autowired
    private IProductTableService productTableService;

    @Autowired
    private IFundTableService fundTableService;

    @Autowired
    private IPrInvestorTableService investorTableService;

    @Resource
    private ExtTlFundRouteLogMapper fundRouteLogMapper;

    @Autowired
    private IInvestorCustomerLimitService investorCustomerLimitService;

    @Lazy
    @Autowired
    private IAnyTxnParamService anyTxnParamService;

    @Lazy
    @Autowired
    private IInnerGatewayService innerGatewayService;

    @Autowired
    private IInvestorLoanService investorLoanApproveService;

    @Autowired
    private IOrganizationTableService organizationTableService;

    @Autowired
    private ICustomerService customerService;

    @Lazy
    @Autowired
    private IUserApiService userApiService;

    @Autowired
    private ISegmentService segmentService;

    @Autowired
    private GrayVersionConfig grayVersionConfig;

    /**
     * 联合贷资金源路由
     *
     * @param fundRouteLog 资金源路由记录
     * @return InvestorFundRouteBean 资金源路由结果
     * @throws Exception
     * @author liuyang
     * @date 2020-06-04
     */
    @Override
    public InvestorFundRouteBean fundRoute(TlFundRouteLog fundRouteLog) throws Exception {

        logger.info("资金源路由开始：{}", JsonUtils.toJSon(fundRouteLog));

        // 初始化对象
        List<TlFundRestraintLog> fundRestraintLogs = new ArrayList<>();
        List<TlInvestorLoanApproveLog> investorLoanApproveLogs = new ArrayList<>();
        InvestorFundRouteBean bean = new InvestorFundRouteBean();
        String tenantId = fundRouteLog.getTenantId();
        String productId = fundRouteLog.getProductId();
        String channel = fundRouteLog.getChannel();
        String seqNo = fundRouteLog.getSeqNo();
        String fundId = null;
        String investorId = null;
        String customerId = fundRouteLog.getCustomerId();

        // 获取业务日期
        PrOrganizationTable organization = organizationTableService.findByOrId(fundRouteLog.getOrganizationId(), tenantId);
        Date businessDate = organization.getNextProcessingDate();

        // 获取客户信息
        CustomerRes customerRes = customerService.getCustomerByChannelAndCustomerIdAndTensnId(channel, customerId, tenantId);

        // 根据产品id获取产品资源配置信息
        List<PrProductFund> productFunds = productTableService.findFundByProductId(productId, tenantId);
        productFunds.sort(Comparator.comparing(PrProductFund::getPriority, Comparator.reverseOrder()));

        for (int i = 0; i < productFunds.size(); i++) {

            // 出资方恢复Set
            Set<InvestorRecoverBean> investorRecoverBeanSet = new HashSet<>();

            PrProductFund productFund = productFunds.get(i);

            // 获取资金源信息
            FundTableRes fundTableRes = fundTableService.findByFundIdAndTenId(tenantId, productFund.getFundId());
            // 如果资金源状态为不正常则跳过该资金源
            if (!TransBizConstant.STATUS_1.equals(fundTableRes.getTableStatus())) {
                continue;
            }

            BigDecimal amount = fundRouteLog.getLoanAmount();
            List<PrFundFactor> fundFactors = fundTableRes.getControllerReqList();
            fundFactors.sort(Comparator.comparing(PrFundFactor::getOffsetFlag));
            int fundCount = 0; // 统计满足要求的资金方
            int routeOrder = i + 1;
            int totalFundCount = fundFactors.size(); // 资金方个数
            for (PrFundFactor fundFactor : fundFactors) {

                investorId = fundFactor.getInvestorId();

                // 去除本行
                if (TransBizConstant.BANK_INVESTOR_ID.equals(investorId)) {
                    totalFundCount--;
                    continue;
                }

                // 计算资金方的借款金额
                BigDecimal investorAmount = null;
                if (TransBizConstant.OFFSET_1.equals(fundFactor.getOffsetFlag())) {
                    investorAmount = amount;
                } else {
                    investorAmount = amount.multiply(fundFactor.getInvertorPercentage()).setScale(CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP);
                    amount = amount.subtract(investorAmount);
                }

                // 获取资金方信息
                PrInvestorTable investorTable = investorTableService.findInvestorByInvestorId(investorId, tenantId);
                // 如果资金方的状态不正常则跳过该资金源
                if (!TransBizConstant.STATUS_1.equals(investorTable.getTableStatus())) {
                    // 出资方放款审批
                    this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_STATUS_NOT_NORMAL.getFormatMsg(investorId));
                    break;
                }

                // 判断出资方是否有客户的授信通过的记录，如果有则继续后续流程，如果没有则跳过该资金源
                List<TlCustomerInvestorLimit> customerInvestorLimits = investorCustomerLimitService.findByCustomerIdAndInvestorId(customerId, investorId, tenantId, Collections.singletonList(TransBizConstant.LIMIT_STATUS_1));
                if (CollectionUtils.isEmpty(customerInvestorLimits)) {
                    // 出资方放款审批
                    this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_NOT_CREDIT.getFormatMsg(investorId));
                    break;
                }

                // 如果资金方出资金额小于单笔贷款最小值，大于单笔贷款最大值则跳过该资金源
                if ((investorTable.getSingleMinLimit() != null && investorAmount.compareTo(investorTable.getSingleMinLimit()) < TransBizConstant.ZERO)
                        || (investorTable.getSingleMaxLimit() != null && investorAmount.compareTo(investorTable.getSingleMaxLimit()) > TransBizConstant.ZERO)) {
                    // 出资方放款审批
                    this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_AMOUNT_WRONG.getFormatMsg(investorId));
                    break;
                }

                // 占用出资方可用总额度，日可用额度
                HandleInvestorLimitReq req = null;
                try {
                    req = new HandleInvestorLimitReq(tenantId, seqNo, channel, investorId, productId, investorAmount, Constant.INVESTOR_LIMIT_CREDITTYPE_L, Constant.INVESTOR_LIMIT_USETYPE_U);
                    TxnRespResult<HandleInvestorLimitRes> txnResp = anyTxnParamService.handleInvestorLimit(req);
                    if (txnResp == null || TransBizConstant.GATEWAY_SUC != txnResp.getCode() || !TransBizConstant.USE_RESULT_S.equals(txnResp.getData().getUseResult())) {
                        logger.error("出资方[{}],借款额度占用异常：{}", investorId, JsonUtils.toJSon(txnResp));
                        // 出资方放款审批
                        this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_AMOUNT_EXCEPTION.getFormatMsg(investorId));
                        break;
                    }
                } catch (Exception e) {
                    // 如果占用出资方可用总额度，日可用额度异常，跳过该资金源
                    logger.error("放款流水号[{}]，出资方[{}]占用出资方可用总额度，日可用额度异常：{}", seqNo, investorId, e);
                    // 出资方放款审批
                    this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_AMOUNT_EXCEPTION.getFormatMsg(investorId));
                    break;
                }

                // 保存冻结的资金限制流水
                TlFundRestraintLog fundRestraintLog01 = investorLoanApproveService.buildTlFundRestraintLog(investorTable, fundRouteLog, investorAmount, fundFactor.getFundId(), TransBizConstant.FREEZE_OPTION_TYPE_01, businessDate, SeqUtils.getSNByLength(32));

                // 调用资金冻结接口
                String restraintStatus = null;
                try {
                    CoreRequest10 req10 = this.buildCoreRequest10(investorTable.getPrepaidAccount(), TransBizConstant.FREEZE_OPTION_TYPE_01, fundRestraintLog01.getRestraintNo(), investorAmount, tenantId, fundRestraintLog01.getSeqNo());
                    ApiResponse<CoreResponse10> resp10 = innerGatewayService.freezeAccount(JsonUtils.toJSon(req10));
                    if (resp10 != null && TransBizConstant.GATEWAY_SUC == resp10.getCode() && TransBizConstant.DEAL_STATE_S.equals(resp10.getData().getDealState())) {
                        restraintStatus = TransBizConstant.RESTRAINT_STATUS_1;
                    } else {
                        logger.error("出资方[{}]额度冻结异常：{}", investorId, JsonUtils.toJSon(resp10));
                        restraintStatus = TransBizConstant.RESTRAINT_STATUS_0;
                    }
                } catch (Exception e) {
                    logger.error("放款流水号[{}]，出资方[{}]额度冻结异常：{}", seqNo, investorId, e);
                    restraintStatus = TransBizConstant.RESTRAINT_STATUS_0;
                }
                fundRestraintLog01.setRestraintStatus(restraintStatus);// 限制状态
                fundRestraintLogs.add(fundRestraintLog01);

                // 出资方放款审批
                String approveStatus = null;
                if (TransBizConstant.RESTRAINT_STATUS_1.equals(restraintStatus)) {
                    approveStatus = this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, null);
                    // 如果放款审批失败则解冻出资方额度
                    if (!TransBizConstant.APPROVE_STATUS_S.equals(approveStatus)) {
                        // 保存解冻的资金限制流水
                        TlFundRestraintLog fundRestraintLog03 = investorLoanApproveService.buildTlFundRestraintLog(investorTable, fundRouteLog, investorAmount, fundFactor.getFundId(), TransBizConstant.FREEZE_OPTION_TYPE_03, businessDate, fundRestraintLog01.getRestraintNo());
                        try {
                            CoreRequest10 req10 = this.buildCoreRequest10(investorTable.getPrepaidAccount(), TransBizConstant.FREEZE_OPTION_TYPE_03, fundRestraintLog03.getRestraintNo(), investorAmount, tenantId, fundRestraintLog03.getSeqNo());
                            ApiResponse<CoreResponse10> resp10 = innerGatewayService.freezeAccount(JsonUtils.toJSon(req10));
                            if (resp10 != null && TransBizConstant.GATEWAY_SUC == resp10.getCode() && TransBizConstant.DEAL_STATE_S.equals(resp10.getData().getDealState())) {
                                restraintStatus = TransBizConstant.RESTRAINT_STATUS_3;
                            } else {
                                logger.error("出资方[{}]额度解冻异常：{}", investorId, JsonUtils.toJSon(resp10));
                                restraintStatus = TransBizConstant.RESTRAINT_STATUS_2;
                            }
                        } catch (Exception e) {
                            logger.error("放款流水号[{}]，出资方[{}]额度解冻异常：{}", seqNo, investorId, e);
                            restraintStatus = TransBizConstant.RESTRAINT_STATUS_2;
                        }
                        fundRestraintLog03.setRestraintStatus(restraintStatus);
                        fundRestraintLogs.add(fundRestraintLog03);
                    }
                } else {
                    approveStatus = this.loanInvestorApprove(investorLoanApproveLogs, fundRouteLog, investorTable, customerRes, investorAmount, productFund.getFundId(), routeOrder, TxnRespCode.INVESTOR_AMOUNT_FREEZE_FAIL.getFormatMsg(investorId));
                }

                // 如果资金方放款审核未通过或者已发起未通过，则恢复该出资方额度，并且跳过该资金源
                if (TransBizConstant.RESTRAINT_STATUS_0.equals(restraintStatus) || !TransBizConstant.APPROVE_STATUS_S.equals(approveStatus)) {
                    try {
                        req = new HandleInvestorLimitReq(tenantId, seqNo, channel, investorId, productId, investorAmount, Constant.INVESTOR_LIMIT_CREDITTYPE_L, Constant.INVESTOR_LIMIT_USETYPE_R);
                        TxnRespResult<HandleInvestorLimitRes> txnResp = anyTxnParamService.handleInvestorLimit(req);
                        if (txnResp == null || TransBizConstant.GATEWAY_SUC != txnResp.getCode() || !TransBizConstant.USE_RESULT_S.equals(txnResp.getData().getUseResult())) {
                            logger.error("出资方[{}],借款额度恢复异常：{}", investorId, JsonUtils.toJSon(txnResp));
                        }
                        break;
                    } catch (Exception e) {
                        // 如果恢复异常，打印异常日志，跳过该资金源
                        logger.error("放款流水号[{}]，出资方[{}]恢复出资方可用总额度，日可用额度异常：{}", seqNo, investorId, e);
                        break;
                    }
                }
                fundCount++;
                InvestorRecoverBean investorRecoverBean = new InvestorRecoverBean();
                investorRecoverBean.setHandleInvestorLimitReq(new HandleInvestorLimitReq(tenantId, seqNo, channel, investorId, productId, investorAmount, Constant.INVESTOR_LIMIT_CREDITTYPE_L, Constant.INVESTOR_LIMIT_USETYPE_R));
                investorRecoverBean.setCoreRequest10(this.buildCoreRequest10(investorTable.getPrepaidAccount(), TransBizConstant.FREEZE_OPTION_TYPE_03, fundRestraintLog01.getRestraintNo(), investorAmount, tenantId, null));
                investorRecoverBean.setFundRestraintLog(fundRestraintLog01);
                investorRecoverBeanSet.add(investorRecoverBean);
            }
            if (fundCount == totalFundCount) {
                fundId = productFund.getFundId(); // 资金源id
                break;
            } else {
                if (CollectionUtils.isNotEmpty(investorRecoverBeanSet)) {
                    // 如果该资金源路由失败则其下的路由成功的出资方需要解冻和恢复额度操作
                    this.recoverInvestor(investorRecoverBeanSet, fundRestraintLogs);
                }
            }

        }

        logger.info("资金源路由结果：{}", fundId);

        // 通知api资金源路由结果
//        String routeStatus = this.noticeApiFundResult(fundRouteLog, fundId);

        // 组装返回结果
        TlFundRouteLog updateFundRouteLog = new TlFundRouteLog();
        updateFundRouteLog.setId(fundRouteLog.getId());
        updateFundRouteLog.setTenantId(fundRouteLog.getTenantId());
        updateFundRouteLog.setOrganizationId(fundRouteLog.getOrganizationId());
        updateFundRouteLog.setCustomerId(customerId);
        updateFundRouteLog.setFundId(fundId);
        updateFundRouteLog.setRouteStatus(TransBizConstant.ROUTE_STATUS_T);
        bean.setUpdateFundRouteLog(updateFundRouteLog); // 放款资金源路由记录
        bean.setFundRestraintLogs(fundRestraintLogs); // 资金限制流水
        bean.setInvestorLoanApproveLogs(investorLoanApproveLogs); // 放款出资方审批记录

        return bean;
    }

    /**
     * 保存联合贷资金源路由请求
     *
     * @param saveFundRouteReq 资金源路由请求
     * @return SaveFundRouteRes 联合贷资金源路由结果
     * @throws TxnBizException
     * @author liuyang
     * @date 2020-06-04
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public SaveFundRouteRes saveFundRoute(SaveFundRouteReq saveFundRouteReq) throws TxnBizException {

        SaveFundRouteRes res = new SaveFundRouteRes();
        res.setUserId(saveFundRouteReq.getUserId());

        CustomerSecondLevelRes customerSecond = customerService.getByUserIdAndChannel(saveFundRouteReq.getUserId(), saveFundRouteReq.getChannel(), saveFundRouteReq.getTenantId());
        TlFundRouteLog fundRouteLog = BeanMapping.copy(saveFundRouteReq, TlFundRouteLog.class);
        try {
            fundRouteLog.setId(segmentService.getId(TransBizConstant.TL_FUND_ROUTE_LOG)); // 主键id
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        fundRouteLog.setCustomerId(customerSecond.getCustomerId()); // 客户id
        fundRouteLog.setOrganizationId(customerSecond.getOrganizationId()); // 机构id
        fundRouteLog.setRouteStatus(TransBizConstant.ROUTE_STATUS_D); // 路由状态 D=待发起路由
        fundRouteLog.setUpdateBy(saveFundRouteReq.getUserId()); // 最后更新操作员 请求中的用户编号
        fundRouteLog.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER); // 记录版本号 初始固定值：1
        fundRouteLog.setGrayVersion(grayVersionConfig.getCurrentVersion());
        fundRouteLogMapper.insertSelective(fundRouteLog);

        return res;
    }

    /**
     * 构建账户冻结/解冻请求实体
     *
     * @param acctNo     账号
     * @param optionType 操作类型
     * @param freezeNo   资金冻结编号
     * @param freezeAmnt 冻结金额
     * @param tenantId   租户id
     * @param serviceSeq 请求流水号
     * @return CoreRequest10 账户冻结/解冻请求实体
     * @throws Exception
     * @author liuyang
     * @date 2020-06-16
     */
    private CoreRequest10 buildCoreRequest10(String acctNo, String optionType, String freezeNo, BigDecimal freezeAmnt, String tenantId, String serviceSeq) throws Exception {
        CoreRequest10 req = new CoreRequest10();
        req.setServiceId(TransBizConstant.GATEWAY_SERVICE_ID); // 请求系统Id
        req.setServiceIp(InternetUtils.getLocalIp()); // 请求ip地址
        req.setTenantId(tenantId); // 租户Id
        req.setServiceSeq(serviceSeq); // 请求流水号
        req.setAcctNo(acctNo);//账号
        req.setFreezeArray(Arrays.asList(new FreezeInfo(optionType, freezeNo, String.valueOf(freezeAmnt), null, null, null))); // 冻结列表
        return req;
    }

    /**
     * 构建合作行放款审批请求实体
     *
     * @param fundRouteLog 资金源路由记录
     * @param investorId   出资方id
     * @param customerRes  客户信息
     * @param loanAmount   贷款金额
     * @return PartnerRequest01 合作行放款审批请求实体
     * @throws Exception
     * @author liuyang
     * @date 2020-06-16
     */
    private PartnerRequest01 buildPartnerRequest01(TlFundRouteLog fundRouteLog, String investorId, CustomerRes customerRes, BigDecimal loanAmount) throws Exception {

        CustomerFirstLevelRes firstLevel = customerRes.getFirstLevel();
        CustomerSecondLevelRes secondLevel = customerRes.getSecondLevel();

        PartnerRequest01 req = new PartnerRequest01();
        req.setServiceId(TransBizConstant.GATEWAY_SERVICE_ID); // 请求系统Id
        req.setServiceIp(InternetUtils.getLocalIp()); // 请求ip地址
        req.setTenantId(fundRouteLog.getTenantId()); // 租户Id
        req.setServiceSeq(SeqUtils.getSN()); // 请求流水号
        req.setInvestorId(investorId); // 出资方ID
        req.setProductNo(fundRouteLog.getProductId()); // 产品号
        req.setIdNumber(firstLevel.getIdNumber()); // 证件号
        req.setMobileNo(secondLevel.getMobile()); // 手机号
        req.setLoanAmount(String.valueOf(loanAmount)); // 借款金额
        req.setContractNo(fundRouteLog.getContractNumber()); // 合同号
        req.setAmortMethod(fundRouteLog.getAmortMethod()); // 还款方式
        req.setLoanUse(fundRouteLog.getLoanUse()); // 贷款用途
        req.setTenor(String.valueOf(fundRouteLog.getTenor())); // 期数
        req.setSeqNo(fundRouteLog.getSeqNo()); // 放款流水号
        return req;
    }

    /**
     * 通知api资金源路由结果
     *
     * @param fundRouteLog 资金源路由记录
     * @param fundId       资金源id
     * @return String 路由结果
     * @throws Exception
     * @author liuyang
     * @date 2020-06-16
     */
    @Override
    public String noticeApiFundResult(TlFundRouteLog fundRouteLog, String fundId) throws Exception {

        FunResultCallBackRequest req = new FunResultCallBackRequest();
        req.setReqSeq(fundRouteLog.getSeqNo());  // 请求流水号
        req.setTenantId(fundRouteLog.getTenantId()); // 租户Id
        req.setChannelNo(fundRouteLog.getChannel()); // 渠道号
        req.setUserId(fundRouteLog.getUserId()); // 用户Id
        req.setLoanSeq(fundRouteLog.getSeqNo()); // 借款流水号
        req.setFunStatus(StringUtils.isNotEmpty(fundId) ? "1" : "0"); // 结果状态
        req.setFunId(fundId); // 资金源Id

        // 路由结果
        String routeStatus = StringUtils.isNotEmpty(fundId) ? TransBizConstant.ROUTE_STATUS_S : TransBizConstant.ROUTE_STATUS_F;

        try {
            logger.info("通知api资金源路由结果：{}", JsonUtils.toJSon(req));
            // 通知api
            ApiResponse resp = userApiService.funResultCallBack(JsonUtils.toJSon(req));
            logger.info("api返回结果：{}", JsonUtils.toJSon(resp));

            // 如果通知失败，设置路由结果为"T"
            if (resp == null || resp.getCode() != 1000) {
                routeStatus = TransBizConstant.ROUTE_STATUS_T;
            }
        } catch (Exception e) {
            logger.info("通知api资金源路由结果异常：{}", e);
            routeStatus = TransBizConstant.ROUTE_STATUS_T;
        }

        return routeStatus;
    }


    /**
     * 合作方放款审核
     *
     * @param investorLoanApproveLogs 放款审批结果
     * @param fundRouteLog            资金源路由信息
     * @param investorTable           出资方信息
     * @param customerRes             客户信息
     * @param investorAmount          出资方金额
     * @param fundId                  资金源id
     * @param routeOrder              路由顺序
     * @param resultMessage           结果信息
     * @return String 审批结果
     * @throws Exception
     * @author liuyang
     * @date 2020-07-07
     */
    private String loanInvestorApprove(List<TlInvestorLoanApproveLog> investorLoanApproveLogs, TlFundRouteLog fundRouteLog, PrInvestorTable investorTable, CustomerRes customerRes, BigDecimal investorAmount, String fundId, Integer routeOrder, String resultMessage) throws Exception {

        // 如果需要进行放款审核
        if (TransBizConstant.LOAN_APPROVE_FLAG_2.equals(investorTable.getLoanApproveFlag())) {

            String approveStatus = TransBizConstant.APPROVE_STATUS_F;

            // 构建放款出资方审批结果
            TlInvestorLoanApproveLog investorLoanApproveLog = investorLoanApproveService.buildTlInvestorLoanApproveLog(fundRouteLog, customerRes, investorTable.getInvestorId(), investorAmount, fundId, routeOrder, resultMessage);
            // 如果没有出现错误则调用合作方的放款审批
            if (StringUtils.isEmpty(resultMessage)) {
                // 资金方放款审核
                PartnerRequest01 req01 = this.buildPartnerRequest01(fundRouteLog, investorTable.getInvestorId(), customerRes, investorAmount);
                ApiResponse<BaseApiResponse> resp01 = innerGatewayService.partnerLoanApprove(JsonUtils.toJSon(req01));

                // 取得放款审批状态
                if (resp01 != null && resp01.getData() != null && TransBizConstant.APPROVE_STATUS_S.equals(resp01.getData().getDealState())) {
                    approveStatus = TransBizConstant.APPROVE_STATUS_S;
                } else {
                    resultMessage = TxnRespCode.INVESTOR_LOAN_APPROVE_FAIL.getFormatMsg(investorTable.getInvestorId());
                }
            }
            investorLoanApproveLog.setApproveStatus(approveStatus);// 审批状态
            investorLoanApproveLog.setResultMessage(resultMessage); // 结果信息
            investorLoanApproveLogs.add(investorLoanApproveLog);

            return approveStatus;
        }

        return TransBizConstant.APPROVE_STATUS_S;
    }

    /**
     * 恢复出资方额度
     *
     * @param investorRecoverBeanSet
     * @param fundRestraintLogs
     */
    private void recoverInvestor(Set<InvestorRecoverBean> investorRecoverBeanSet, List<TlFundRestraintLog> fundRestraintLogs) throws TxnBizException {
        for (InvestorRecoverBean req : investorRecoverBeanSet) {

            HandleInvestorLimitReq handleInvestorLimitReq = req.getHandleInvestorLimitReq();
            CoreRequest10 coreRequest10 = req.getCoreRequest10();
            TlFundRestraintLog fundRestraintLog = req.getFundRestraintLog();

            // 恢复占用的出资方额度
            anyTxnParamService.handleInvestorLimit(handleInvestorLimitReq);

            // 解冻出资方额度
            String restraintStatus;
            // 构建解冻的限制流水
            TlFundRestraintLog fundRestraintLog03 =  investorLoanApproveService.buildTlFundRestraintLog(fundRestraintLog, TransBizConstant.FREEZE_OPTION_TYPE_03, fundRestraintLog.getRestraintNo());
            try {
                coreRequest10.setServiceSeq(fundRestraintLog03.getSeqNo());
                ApiResponse<CoreResponse10> resp10 = innerGatewayService.freezeAccount(JsonUtils.toJSon(coreRequest10));
                if (resp10 != null && TransBizConstant.GATEWAY_SUC == resp10.getCode() && TransBizConstant.DEAL_STATE_S.equals(resp10.getData().getDealState())) {
                    restraintStatus = TransBizConstant.RESTRAINT_STATUS_3;
                } else {
                    logger.error("出资方[{}]额度解冻异常：{}", handleInvestorLimitReq.getInvestorId(), JsonUtils.toJSon(resp10));
                    restraintStatus = TransBizConstant.RESTRAINT_STATUS_2;
                }
            } catch (Exception e) {
                logger.error("出资方[{}]额度解冻异常：{}", handleInvestorLimitReq.getInvestorId(), e);
                restraintStatus = TransBizConstant.RESTRAINT_STATUS_2;
            }
            fundRestraintLog03.setRestraintStatus(restraintStatus);
            fundRestraintLogs.add(fundRestraintLog03);
        }
    }

}
